package com.fsnbigdata.security.auth;

import com.fsnbigdata.domain.security.User;
import com.fsnbigdata.service.api.LogService;
import com.fsnbigdata.service.api.UserService;
import com.fsnbigdata.util.Email;
import com.fsnbigdata.util.IPTOAddress;
import com.fsnbigdata.util.PublicStaticData;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by fan.jin on 2016-10-19.
 */
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final Log logger = LogFactory.getLog(this.getClass());

    private TokenHelper tokenHelper;

    private UserDetailsService userDetailsService;

    private UserService userService;

    private LogService logService;

    public TokenAuthenticationFilter(TokenHelper tokenHelper, UserDetailsService userDetailsService,UserService userService,LogService logService) {
        this.tokenHelper = tokenHelper;
        this.userDetailsService = userDetailsService;
        this.userService = userService;
        this.logService = logService;
    }


    @Override
    public void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain
    ) throws IOException, ServletException {

        String username;
        String authToken = tokenHelper.getToken(request);
        if (authToken != null) {
            // get username from token
            username = tokenHelper.getUsernameFromToken(authToken);
            if (username != null) {
                // get user
                String sign = tokenHelper.getSign(authToken);
                String path = request.getServletPath();
                if(path!=null&&!"OPTIONS".equals(request.getMethod())&&path.indexOf("refresh")==-1){
                    //单终端登录，杨鑫end
                    Object number = PublicStaticData.userSign.get(username);
                    if(number==null||"".equals(number+"")){
                        number = sign;
                        PublicStaticData.userSign.put(username,number);
                    }
                    if(sign!=null&&(!sign.equals(number+""))){
                        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "用户已在其他位置登录");
                        return;
                    }
                    //单终端登录，杨鑫start

                    //限制一段时间内的访问次数，杨鑫start
                    Object access = PublicStaticData.accessCount.get(username);
                    if(access==null||"".equals(access+"")){
                        PublicStaticData.accessCount.put(username,new Date().getTime()+","+1+","+0);
                    }else {
                        String[] accesss = access.toString().split(",");
                        long time = Long.parseLong(accesss[0]);
                        int count = Integer.parseInt(accesss[1]);
                        int emailStatus = Integer.parseInt(accesss[2]);
                        long nowTime = new Date().getTime();
                        //如果再次访问的时间小于清空统计次数时间的值
                        if(nowTime-time< PublicStaticData.ACCESS_TIME){
                            //如果访问计数大于限制次数
                            if(count>= PublicStaticData.ACCESS_NUMBER){
                                //返回402，表示频繁请求
                                response.sendError(HttpServletResponse.SC_PAYMENT_REQUIRED,"频繁请求,稍后再试！");
                                if(emailStatus==0){
                                    try {
                                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        com.fsnbigdata.domain.Log log = new com.fsnbigdata.domain.Log();
                                        log.setAddress(IPTOAddress.addr(IPTOAddress.getIP(request)));
                                        log.setClientInformation(IPTOAddress.getAddr(request));
                                        log.setIp(IPTOAddress.getIP(request));
                                        log.setType("warning");
                                        log.setGenre("2");
                                        log.setUsername(username);
                                        log.setDescription(username+"在"+sdf.format(time)+"至"+sdf.format(nowTime)+"这段时间内发起了频繁请求！");
                                        log.setCreateTime(new Date());
                                        logService.save(log);
                                    }catch (Exception e){
                                        System.out.println(e.getMessage());
                                    }
                                    Email email = new Email();
                                    User user = userService.findByUsername("admin");
                                    try {
                                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                                        email.sendMailToAdminByException(user.getEmail(),PublicStaticData.EMAIL_SENDER,sdf.format(time), sdf.format(nowTime),username, PublicStaticData.ACCESS_NUMBER);
                                        PublicStaticData.accessCount.put(username,new Date().getTime()+","+count+","+1);
                                        logger.debug("邮件发送成功！");
                                    }catch (Exception e){
                                        logger.debug("邮件发送失败，失败原因："+e.getMessage());
                                    }
                                }
                                return;
                            }
                            //继续计数
                            count++;
                            //放入统计集合中
                            PublicStaticData.accessCount.put(username,time+","+count+","+0);
                        }else {
                            //重置用户统计信息
                            PublicStaticData.accessCount.put(username,new Date().getTime()+","+1+","+0);
                        }
                    }
                }
                //限制一段时间内的访问次数，杨鑫end
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                if (tokenHelper.validateToken(authToken, userDetails)) {
                    // create authentication
                    TokenBasedAuthentication authentication = new TokenBasedAuthentication(userDetails);
                    authentication.setToken(authToken);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }


        chain.doFilter(request, response);
    }

}